package whut.GA;

import org.apache.commons.math3.util.FastMath;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Justin on 2018-04-23
 */
public class BinaryEncoder implements IBinaryEncoder {
    public double M; //小数部分
    public double N; //整数部分;
    public int L ;//编码长度

    public BinaryEncoder() {
        new BinaryEncoder(10, 2);
    }

    public BinaryEncoder(int m, int n) {
        M = FastMath.pow(10, m);
        N = FastMath.pow(10, n);
        L = (int) (FastMath.log(2,  M * N ) + 0.5);
    }

    public List<Integer> coding(double[] value){
        List<Integer> result = new ArrayList<>();
        for (double item : value) {
            // for debug
            if (FastMath.abs(item) > N) {
                System.err.println("doubles2BinaryArray : Value is too large");
                System.exit(-1);
            }

            String eValue = String.format("%.15e",item);

            long longLoc = FastMath.round((N + item) * M);
            char[] binLoc = Long.toUnsignedString(longLoc,2).toCharArray();
            int m = binLoc.length;

            for (int i = 0; i < L - m; i++) {
                result.add(0);
            }
            for (char c : binLoc) {
                result.add(c - '0');
            }
        }
        return result;
    }

    public double[] decoding(List<Integer> value){
        int m = value.size() / L;
        if (value.size() != m * L) {
            System.err.println("the length is not a multiple of " + L);
            System.exit(-1);
        }
        double[] result = new double[m];
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < value.size(); i++) {
            s.append(value.get(i));
        }

        for (int i = 0; i < m; i++) {
            int a = i * L;
            int b = (i + 1) * L;

            String subStr = s.substring(a, b);
            long sub = Long.parseUnsignedLong(subStr, 2);
            double d = (double) sub / (M * N);
            d = d - (int) d;
            result[i] = d * N;
        }
        return result;
    }
}
